package drds.plus.sql_process.abstract_syntax_tree.node.query;

import drds.plus.sql_process.abstract_syntax_tree.ObjectCreateFactory;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import drds.plus.sql_process.abstract_syntax_tree.node.Node;
import drds.plus.sql_process.abstract_syntax_tree.node.query.build.QueryBuilder;
import drds.plus.sql_process.abstract_syntax_tree.node.query.build.QueryMergeBuilder;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

public class MergeQuery extends Query {
    @Setter
    @Getter
    private QueryMergeBuilder mergeQueryNodeBuilder;
    @Setter
    @Getter
    private boolean sharded = true;
    @Setter
    @Getter
    private boolean union = false;
    /**
     * 是否是groupBy分库键
     */
    @Setter
    @Getter
    private boolean groupByShardColumns = false;

    /**
     * 是否是distinct分库键.distinct column 也是group by列
     */
    @Setter
    @Getter
    private boolean distinctShardColumns = false;
    @Setter
    @Getter
    private boolean dmlByBroadcast = false;

    public MergeQuery() {
        super();
        this.mergeQueryNodeBuilder = new QueryMergeBuilder(this);
    }

    public void build() {
        if (this.isNeedBuild()) {
            this.mergeQueryNodeBuilder.build();
        }

        setNeedBuild(false);
    }

    public MergeQuery merge(Node node) {
        this.addNode(node);
        return this;
    }

    public MergeQuery merge(List<Node> nodeList) {
        this.getNodeList().addAll(nodeList);
        return this;
    }

    public ExecutePlan toExecutePlan(int shareIndex) {
        subQueryToExecutePlan(shareIndex);
        drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery mergeQuery = ObjectCreateFactory.createMergeQuery();
        mergeQuery.setLimitFrom(this.getLimitFrom());
        mergeQuery.setLimitTo(this.getLimitTo());
        mergeQuery.setSelectItemList(this.getSelectItemList());
        mergeQuery.setAlias(this.getAlias());
        mergeQuery.setIsSubQuery(this.isSubQuery());
        mergeQuery.setUnion(this.isUnion());
        mergeQuery.setBroadcastPut(this.isDmlByBroadcast());
        for (Node node : this.getNodeList()) {
            mergeQuery.addExecutePlan(node.toExecutePlan());
        }
        mergeQuery.setOrderByList(this.getOrderByList());
        mergeQuery.setLimitFrom(this.getLimitFrom());
        mergeQuery.setLimitTo(this.getLimitTo());
        mergeQuery.setGroupByList(this.getGroupByList());
        mergeQuery.setSharded(this.isSharded());
        mergeQuery.having(this.getHaving());
        mergeQuery.setOtherJoinOnFilter(this.getOtherJoinOnFilter());
        mergeQuery.setExistAggregate(this.isExistAggregateExpression());
        mergeQuery.setGroupByShardColumns(this.isGroupByShardColumns());
        mergeQuery.setDistinctGroupByShardColumns(this.isDistinctShardColumns());
        mergeQuery.setDataNodeId(this.getDataNodeId(shareIndex));
        mergeQuery.setSubQueryFilterId(this.getSubQueryId());
        mergeQuery.setSubQueryFilter(this.getSubQueryFunctionFilter());
        mergeQuery.setCorrelatedSubQuery(this.isCorrelatedSubQuery());
        mergeQuery.setExistSequenceValue(this.isExistSequenceValue());
        return mergeQuery;
    }

    public List getCompleteOrderByList() {
        if (!(this.getFirstSubNodeQueryNode() instanceof Query)) {
            return new ArrayList<OrderBy>(0);
        }

        List<OrderBy> orderByListCombinedWithGroupBy = getOrderByListCombinedWithGroupByList();
        if (orderByListCombinedWithGroupBy != null) {
            return orderByListCombinedWithGroupBy;
        } else {
            return new ArrayList<OrderBy>(0);
        }
    }

    public QueryBuilder getQueryNodeBuilder() {
        return mergeQueryNodeBuilder;
    }

    public String getName() {
        return this.getAlias();
    }


    public void setGroupByShardColumns(boolean groupByShardColumns) {
        setNeedBuild(true);
        this.groupByShardColumns = groupByShardColumns;

    }


    public void setDistinctShardColumns(boolean shardColumnAllIsGroupByColumn) {
        setNeedBuild(true);
        this.distinctShardColumns = shardColumnAllIsGroupByColumn;

    }

    public MergeQuery copy() {
        MergeQuery mergeQueryNode = new MergeQuery();
        this.copySelfTo(mergeQueryNode);
        for (Node node : this.getNodeList()) {
            mergeQueryNode.merge(node.copy());
        }
        mergeQueryNode.setSharded(sharded);
        mergeQueryNode.setUnion(union);
        mergeQueryNode.setGroupByShardColumns(groupByShardColumns);
        mergeQueryNode.setDistinctShardColumns(distinctShardColumns);
        mergeQueryNode.setBroadcast(broadcast);
        return mergeQueryNode;
    }

    public MergeQuery copySelf() {
        MergeQuery mergeQueryNode = new MergeQuery();
        this.copySelfTo(mergeQueryNode);
        for (Node node : this.getNodeList()) {
            mergeQueryNode.merge(node.copySelf());
        }
        mergeQueryNode.setSharded(sharded);
        mergeQueryNode.setUnion(union);
        mergeQueryNode.setGroupByShardColumns(groupByShardColumns);
        mergeQueryNode.setDistinctShardColumns(distinctShardColumns);
        mergeQueryNode.setBroadcast(broadcast);
        return mergeQueryNode;
    }

    public MergeQuery deepCopy() {
        MergeQuery mergeQueryNode = new MergeQuery();
        this.deepCopySelfTo(mergeQueryNode);
        for (Node node : this.getNodeList()) {
            mergeQueryNode.merge(node.deepCopy());
        }
        mergeQueryNode.setSharded(sharded);
        mergeQueryNode.setUnion(union);
        mergeQueryNode.setGroupByShardColumns(groupByShardColumns);
        mergeQueryNode.setDistinctShardColumns(distinctShardColumns);
        mergeQueryNode.setBroadcast(broadcast);
        return mergeQueryNode;
    }

}
